Skip to content

fix(cli): setup scripts use docker mode + increase health timeout - #397

Closed
alfredo1996 wants to merge 6 commits into
release/1.1from
fix/cli-setup-reliability
Closed

fix(cli): setup scripts use docker mode + increase health timeout#397
alfredo1996 wants to merge 6 commits into
release/1.1from
fix/cli-setup-reliability

Conversation

@alfredo1996

@alfredo1996 alfredo1996 commented Apr 6, 2026

Copy link
Copy Markdown
Owner

Scripts used --mode local (skipped Docker). Neo4j cold start timed out at 60s. Fixed both.

Summary by CodeRabbit

  • Chores

    • Increased default health-check polling interval and extended timeout
    • Simplified setup/demo CLI invocation by removing explicit mode flags
    • Improved Docker command invocation behavior
  • Behavior Changes

    • Migrations now resolve DATABASE_URL from local env or project config and run via a single path
    • Start now accepts a "full" option; Docker-mode defaults to DB-only unless full=true; banner messaging updated
    • Neo4j readiness now uses container health status (non-local)
    • Demo/setup/seeding now propagate "full" and Docker-network flags to downstream steps
  • Tests

    • Updated tests to reflect new startup, migrate, seed, and readiness behaviors

- scripts/setup.sh and setup-local-demo.sh now use docker mode
  (default) instead of --mode local which skips Docker containers
- Health check timeout increased from 60s to 120s — Neo4j cold start
  from empty volumes takes 90-120s
- Health check interval increased from 1s to 2s — less polling noise

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Apr 6, 2026

Copy link
Copy Markdown

Caution

Review failed

Pull request was closed or merged during review

Walkthrough

Consolidates startup/mode handling and DB access: removes explicit --mode local in scripts, makes Docker start optionally DB-only, changes Neo4j readiness to use Docker health status, always runs migrations via npx drizzle-kit with resolved DATABASE_URL, and increases health-check defaults (interval/timeout).

Changes

Cohort / File(s) Summary
Health Defaults
cli/src/lib/health.ts
Default polling interval increased 1000ms → 2000ms; default timeout increased 60_000ms → 120_000ms.
Shell invocations
scripts/setup-local-demo.sh, scripts/setup.sh
Removed explicit --mode local from CLI invocations; CLI call sites no longer pass mode flag.
Start / Compose
cli/src/commands/start.ts, cli/src/__tests__/commands/start.test.ts
runStart accepts StartOptions.full?; Docker startup now supports full: true or full: false (DB-only default); tests updated to expect { full: false }.
Setup / Demo wiring
cli/src/commands/setup.ts, cli/src/commands/demo.ts, cli/src/__tests__/commands/demo.test.ts
runSetup and runDemo propagate a full flag to runStart; runDemo forces full: true for setup and calls seed with dockerNetwork: true; tests updated for new arg shapes.
DB seed
cli/src/commands/db/seed.ts, cli/src/__tests__/commands/db/seed.test.ts
seedPostgres now accepts dockerNetwork?: boolean and, when true, runs seed with Docker host env overrides (NEO4J_HOST, PG_HOST); runDbSeed accepts and forwards dockerNetwork. Tests updated to assert env passed.
DB migrate (runtime)
cli/src/commands/db/migrate.ts, cli/src/__tests__/commands/db/migrate.test.ts
Removed mode-specific Docker branch; added resolveDatabaseUrl() to prefer .env.local (handles quoted values) or build URL from project config; migrations always run via run("npx drizzle-kit migrate", { cwd: paths.appDir, env: {..., DATABASE_URL} }). Tests updated for env precedence, quoting, and URI-encoding fallback.
Docker exec & Neo4j readiness
cli/src/lib/exec.ts, cli/src/lib/docker.ts, cli/src/__tests__/lib/docker.test.ts
dockerExec now assembles and execs a single shell command string (preserves quoting/whitespace); isNeo4jReady() uses docker inspect --format={{.State.Health.Status}} in non-local mode (expects "healthy"); tests adapted to mock runOrNull output.
Tests (general adjustments)
cli/src/__tests__/*
Multiple tests modified to remove mode-based mocking and to validate new env/arg shapes, file existence/read behavior, and readiness mechanisms (e.g., mocking existsSync, readFileSync, runOrNull, and run).

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant CLI as "CLI (runStart)"
    participant Compose as "composeUp"
    participant Docker as "Docker Engine"
    participant Neo4j as "neoboard-neo4j"

    User->>CLI: runStart(opts?)
    CLI->>Compose: composeUp({ full: opts?.full ?? false })
    Compose->>Docker: docker-compose (DB-only or full)
    Docker->>Neo4j: create/start container
    CLI->>Docker: docker inspect --format={{.State.Health.Status}} neoboard-neo4j
    Docker-->>CLI: "healthy" / "starting"
    alt healthy
        CLI->>User: report Neo4j ready
    else not healthy
        CLI->>User: waiting / eventual timeout
    end
Loading
sequenceDiagram
    participant User
    participant CLI as "CLI (db:migrate)"
    participant FS as "Filesystem (.env.local)"
    participant Config as "Project config"
    participant Shell as "child process (npx drizzle-kit)"
    participant Postgres as "Postgres"

    User->>CLI: runDbMigrate()
    CLI->>FS: read paths.envFile
    alt .env.local exists
        FS-->>CLI: DATABASE_URL (strip quotes)
    else missing
        CLI->>Config: readProjectConfig()
        Config-->>CLI: build postgres URL (URI-encoded creds)
    end
    CLI->>Shell: run("npx drizzle-kit migrate", { cwd: paths.appDir, env: {...process.env, DATABASE_URL} })
    Shell->>Postgres: connect using DATABASE_URL
    Postgres-->>Shell: migration result
    Shell-->>CLI: exit status
    CLI->>User: report success/failure
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested labels

enhancement, testing

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main changes: ensuring setup scripts use Docker mode and increasing health check timeout from 60s to 120s to fix Neo4j cold start timeouts.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/cli-setup-reliability

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
scripts/setup-local-demo.sh (1)

20-20: Use explicit Docker mode for demo setup as well.

Line 20 also relies on CLI defaults. Pinning mode here keeps demo setup behavior stable and aligned with the PR intent.

Proposed change
-node "$CLI_BIN" demo
+node "$CLI_BIN" demo --mode docker
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/setup-local-demo.sh` at line 20, The demo setup call currently relies
on CLI defaults (node "$CLI_BIN" demo); update this invocation to explicitly pin
the Docker mode so behavior is stable—call the CLI with the mode flag used
elsewhere (e.g., add the same --mode docker or --docker flag your CLI expects)
when invoking the demo command to ensure consistent Docker-mode behavior for the
demo setup.
scripts/setup.sh (1)

19-19: Make Docker mode explicit to avoid default drift.

Line 19 now depends on the CLI default. For setup reliability, prefer explicit Docker mode so behavior won’t change if defaults change later.

Proposed change
-node "$CLI_BIN" setup
+node "$CLI_BIN" setup --mode docker
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/setup.sh` at line 19, The setup invocation relies on the CLI default
mode; change the call to node "$CLI_BIN" setup to explicitly request Docker mode
(e.g., add the CLI flag that sets mode to docker such as --mode docker or the
project-specific --docker flag) so the script no longer depends on CLI defaults;
update the invocation in scripts/setup.sh (the node "$CLI_BIN" setup line) to
include the explicit Docker-mode flag and ensure any documentation or downstream
automation uses the same explicit flag.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@scripts/setup-local-demo.sh`:
- Line 20: The demo setup call currently relies on CLI defaults (node "$CLI_BIN"
demo); update this invocation to explicitly pin the Docker mode so behavior is
stable—call the CLI with the mode flag used elsewhere (e.g., add the same --mode
docker or --docker flag your CLI expects) when invoking the demo command to
ensure consistent Docker-mode behavior for the demo setup.

In `@scripts/setup.sh`:
- Line 19: The setup invocation relies on the CLI default mode; change the call
to node "$CLI_BIN" setup to explicitly request Docker mode (e.g., add the CLI
flag that sets mode to docker such as --mode docker or the project-specific
--docker flag) so the script no longer depends on CLI defaults; update the
invocation in scripts/setup.sh (the node "$CLI_BIN" setup line) to include the
explicit Docker-mode flag and ensure any documentation or downstream automation
uses the same explicit flag.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: d0dfd9bc-c26f-4d32-a0cf-3ceee71b47a7

📥 Commits

Reviewing files that changed from the base of the PR and between 6baec9b and 3010a1b.

📒 Files selected for processing (3)
  • cli/src/lib/health.ts
  • scripts/setup-local-demo.sh
  • scripts/setup.sh

alfredorubin96 and others added 2 commits April 6, 2026 21:21
…st health

Root causes of slow/broken setup:
1. start.ts used full=true → built entire Next.js Docker image (minutes)
2. db/migrate.ts used docker exec into neoboard-app (doesn't exist)
3. Neo4j health used cypher-shell (slow JVM startup per poll)
4. Scripts hardcoded --mode local (skipped Docker)
5. Health timeout 60s too short for Neo4j cold start

Fixes:
- start.ts: full=false → docker-compose.yml (DBs only, ~30s)
- db/migrate.ts: always runs locally with DATABASE_URL resolved from
  .env.local (priority) or neoboard.config.json (fallback). Works
  whether DB is Docker, local, or remote.
- docker.ts: isNeo4jReady uses docker inspect (instant) not cypher-shell
- health.ts: timeout 60s→120s, interval 1s→2s
- scripts: removed --mode local (uses docker default)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
cli/src/__tests__/lib/docker.test.ts (1)

177-184: Add one trim-behavior test for robustness.

Since isNeo4jReady() trims output, consider adding a case like "healthy\n" to prevent regressions in shell-output handling.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cli/src/__tests__/lib/docker.test.ts` around lines 177 - 184, Add a test case
to cover trimmed shell output: update the test suite for isNeo4jReady to mock
mockRunOrNull returning a value with trailing newline (e.g., "healthy\n") and
assert that isNeo4jReady() still returns true; reference the existing test
helpers/mockRunOrNull and the isNeo4jReady() function so the new case mirrors
the "returns true when docker inspect reports healthy" test but uses a
newline-terminated string to verify trimming behavior.
cli/src/__tests__/commands/db/migrate.test.ts (1)

102-121: Add edge-case tests for URL parsing behavior.

Please add cases for quoted values (e.g., DATABASE_URL="...") and special-character credentials in fallback URL construction. This will protect the new resolver from common .env formatting variations.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cli/src/__tests__/commands/db/migrate.test.ts` around lines 102 - 121, Add
two new test cases in migrate.test.ts alongside the existing runDbMigrate tests:
one where the .env.local DATABASE_URL is quoted (e.g.,
DATABASE_URL="postgresql://user:pass@host:5432/db") to ensure the resolver
strips surrounding quotes when calling runDbMigrate, and another where the
fallback config-derived URL uses credentials containing special characters
(e.g., password with symbols) to verify proper encoding/handling when
constructing DATABASE_URL. Use the existing helpers/mock patterns (runDbMigrate,
mockExistsSync, mockRun) to set up .env content or config inputs and assert
mockRun is called with env containing the expected normalized DATABASE_URL for
each case.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@cli/src/commands/db/migrate.ts`:
- Around line 15-25: The DATABASE_URL parsing currently returns the raw value
(including surrounding quotes) and the fallback builds a connection string
without URI-encoding credentials; update the parsing loop in migrate.ts to strip
any surrounding single or double quotes from the extracted url (trim() then
remove leading/trailing "'" or '"' if present) before returning it, and change
the fallback that uses readProjectConfig() to URI-encode the username and
password (e.g., via encodeURIComponent on config.postgres.user and
config.postgres.password) when constructing the `postgresql://...` string so
reserved characters don’t break the connection string.
- Around line 103-106: Wrap the existing run("npx drizzle-kit migrate", ...)
call with an advisory lock: create a Postgres client, connect, call SELECT
pg_advisory_lock(<constant_bigint>) to acquire a session lock, then execute the
run(...) command while the lock is held, and finally release the lock (SELECT
pg_advisory_unlock(...)) and close the client in a try/finally so the lock is
always released; reference the existing run(...) invocation in migrate.ts and
use a single fixed bigint key (e.g., 1234567890) for pg_advisory_lock/unlock to
serialize concurrent migrations.

---

Nitpick comments:
In `@cli/src/__tests__/commands/db/migrate.test.ts`:
- Around line 102-121: Add two new test cases in migrate.test.ts alongside the
existing runDbMigrate tests: one where the .env.local DATABASE_URL is quoted
(e.g., DATABASE_URL="postgresql://user:pass@host:5432/db") to ensure the
resolver strips surrounding quotes when calling runDbMigrate, and another where
the fallback config-derived URL uses credentials containing special characters
(e.g., password with symbols) to verify proper encoding/handling when
constructing DATABASE_URL. Use the existing helpers/mock patterns (runDbMigrate,
mockExistsSync, mockRun) to set up .env content or config inputs and assert
mockRun is called with env containing the expected normalized DATABASE_URL for
each case.

In `@cli/src/__tests__/lib/docker.test.ts`:
- Around line 177-184: Add a test case to cover trimmed shell output: update the
test suite for isNeo4jReady to mock mockRunOrNull returning a value with
trailing newline (e.g., "healthy\n") and assert that isNeo4jReady() still
returns true; reference the existing test helpers/mockRunOrNull and the
isNeo4jReady() function so the new case mirrors the "returns true when docker
inspect reports healthy" test but uses a newline-terminated string to verify
trimming behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 06804a05-36e2-4260-a686-9ea9a0ac4a8c

📥 Commits

Reviewing files that changed from the base of the PR and between 3010a1b and af31a5e.

📒 Files selected for processing (6)
  • cli/src/__tests__/commands/db/migrate.test.ts
  • cli/src/__tests__/commands/start.test.ts
  • cli/src/__tests__/lib/docker.test.ts
  • cli/src/commands/db/migrate.ts
  • cli/src/commands/start.ts
  • cli/src/lib/docker.ts
✅ Files skipped from review due to trivial changes (1)
  • cli/src/tests/commands/start.test.ts

Comment thread cli/src/commands/db/migrate.ts Outdated
Comment on lines +103 to +106
run("npx drizzle-kit migrate", {
cwd: paths.appDir,
env: { ...process.env, DATABASE_URL: dbUrl },
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

For the drizzle-kit version used by this repository, does drizzle-kit migrate acquire a PostgreSQL advisory lock (or equivalent concurrency lock) to prevent concurrent migration runners?

💡 Result:

I can’t tell what drizzle-kit version “this repository” uses unless you share the repo URL or paste the drizzle-kit entry from package.json / lockfile.

That said, Drizzle Kit’s migrate has historically not taken a PostgreSQL advisory lock (e.g. pg_advisory_lock / pg_advisory_xact_lock) to serialize concurrent runners—the Drizzle team explicitly described a future “proper lock mechanism” as something they will implement, implying it wasn’t present at the time of that design note/discussion. [1] The locks people commonly observe during migrate are standard PostgreSQL DDL locks (e.g., from CREATE TABLE IF NOT EXISTS ... __drizzle_migrations and other DDL), not an explicit migration-runner mutex. [2]

If you paste your repo’s drizzle-kit version, I can verify more precisely for that version and (if needed) point you to how to confirm by searching the installed CLI code for pg_advisory_*.

Sources

  1. Drizzle discussion noting “Proper Lock Mechanism” as a planned improvement for simultaneous migrate() executions: “We will implement a proper lock mechanism…” [1]
  2. Report of DDL locking behavior during Drizzle migrations (table creation causing locks), not advisory-lock coordination: [2]

🏁 Script executed:

fd -t f "package.json" | head -5

Repository: alfredo1996/neoboard

Length of output: 162


🏁 Script executed:

cat package.json | grep -A 2 -B 2 "drizzle"

Repository: alfredo1996/neoboard

Length of output: 46


🏁 Script executed:

# Also check for any advisory lock usage in the codebase
rg "pg_advisory|advisory.*lock" -i

Repository: alfredo1996/neoboard

Length of output: 46


🏁 Script executed:

cat cli/package.json | grep -E "(drizzle|migration)" -i

Repository: alfredo1996/neoboard

Length of output: 46


🏁 Script executed:

# Check for lockfiles to get exact version
fd -t f "(pnpm-lock|package-lock|yarn.lock)" | head -1

Repository: alfredo1996/neoboard

Length of output: 85


🏁 Script executed:

# Search for drizzle across all package files
rg "drizzle-kit" --type json

Repository: alfredo1996/neoboard

Length of output: 561


🏁 Script executed:

# Check cli/package.json for drizzle dependencies
cat cli/package.json

Repository: alfredo1996/neoboard

Length of output: 636


🏁 Script executed:

# Check the full context of the migration command at lines 103-106
cat -n cli/src/commands/db/migrate.ts | sed -n '95,115p'

Repository: alfredo1996/neoboard

Length of output: 643


🏁 Script executed:

# Search for any migration-related files that might have custom locking
fd -t f "migrat" cli/src/ | head -10

Repository: alfredo1996/neoboard

Length of output: 140


🏁 Script executed:

cat -n cli/src/__tests__/commands/db/migrate.test.ts | head -50

Repository: alfredo1996/neoboard

Length of output: 1635


Add advisory locking to prevent concurrent migration races.

drizzle-kit migrate (version 0.31.10) does not implement PostgreSQL advisory locking. Running migrations concurrently can cause race conditions. Wrap the migration call with pg_advisory_xact_lock() or implement an equivalent serialization mechanism to comply with NeoBoard migration requirements.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cli/src/commands/db/migrate.ts` around lines 103 - 106, Wrap the existing
run("npx drizzle-kit migrate", ...) call with an advisory lock: create a
Postgres client, connect, call SELECT pg_advisory_lock(<constant_bigint>) to
acquire a session lock, then execute the run(...) command while the lock is
held, and finally release the lock (SELECT pg_advisory_unlock(...)) and close
the client in a try/finally so the lock is always released; reference the
existing run(...) invocation in migrate.ts and use a single fixed bigint key
(e.g., 1234567890) for pg_advisory_lock/unlock to serialize concurrent
migrations.

alfredorubin96 and others added 3 commits April 6, 2026 21:59
- start.ts accepts { full } option — full=true uses docker-compose.full.yml
  (app + DBs), full=false uses docker-compose.yml (DBs only)
- demo.ts always passes full=true — users get the complete experience
- setup.ts passes full=false by default — developers start DBs,
  then run the app locally with npm run dev

neoboard demo: ~3.5min → full stack in Docker, seeded, ready
neoboard setup + neoboard dev: ~30s → DBs in Docker, app locally

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…entials

Addresses CodeRabbit review:
- Strip surrounding quotes from DATABASE_URL in .env.local
- URI-encode user/password/database in config fallback URL
- Add tests for both edge cases

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@alfredo1996

Copy link
Copy Markdown
Owner Author

Superseded by #414 (combined release 1.1 fixes)

@alfredo1996 alfredo1996 closed this Apr 6, 2026
@sonarqubecloud

sonarqubecloud Bot commented Apr 6, 2026

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
2 Security Hotspots

See analysis details on SonarQube Cloud

@alfredo1996
alfredo1996 deleted the fix/cli-setup-reliability branch April 7, 2026 11:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants